package LDraw.Support;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map.Entry;
import Builder.BuilderConfigurationManager;
import Exports.CompatiblePartManager;
import Exports.PartDomainT;
import Exports.PartIds;
import Resource.ResourceManager;
public class PartCache implements Comparator<String> {
private static PartCache _instance = null;
final static String CACHENAME = BuilderConfigurationManager.getDefaultDataDirectoryPath()+"brick.list";
final static String CATEGORYPATH = BuilderConfigurationManager.getDefaultDataDirectoryPath()+"category.list";
final static String FILEPREFIX = "FILE:";
public synchronized static PartCache getInstance() {
if (_instance == null)
_instance = new PartCache(BuilderConfigurationManager
.getInstance().getLDrawDirectory()
+ LDrawPaths.PARTS_DIRECTORY_NAME);
return _instance;
}
private HashMap<String, ArrayList<String>> categoryToFileCache;
private HashMap<String, String> fileToBrickName;
private HashMap<String, HashMap<String, ArrayList<String>>> searchCacheTable;
private HashMap<String, String> aliasPartNameMap;
private ArrayList<String> categoryList;
boolean isSearchCacheTalbeReady = false;
private PartCache(String partsPath) {
categoryToFileCache = new HashMap<String, ArrayList<String>>();
fileToBrickName = new HashMap<String, String>();
aliasPartNameMap = new HashMap<String, String>();
loadCategoryFromFile();
loadPartInfoToCache(partsPath);
searchCacheTable = new HashMap<String, HashMap<String, ArrayList<String>>>();
initSearchCacheTable();
}
public void reload() {
loadCategoryFromFile();
loadPartInfoToCache(BuilderConfigurationManager.getInstance()
.getLDrawDirectory() + LDrawPaths.PARTS_DIRECTORY_NAME);
}
private void initSearchCacheTable() {
new Thread(new Runnable() {
@Override
public void run() {
String searchText = null;
HashMap<String, ArrayList<String>> map;
for (int i = 0; i < 9; i++) {
searchText = Character.toString((char) ('1' + i));
if (searchCacheTable.containsKey(searchText) == false) {
map = new HashMap<String, ArrayList<String>>();
addCacheItemForSearchCacheTable(map, searchText);
searchCacheTable.put(searchText, map);
}
}
for (int i = 0; i < 26; i++) {
searchText = Character.toString((char) ('A' + i));
}
System.out.println("search Cache table is ready");
isSearchCacheTalbeReady = true;
}
}).start();
}
private void addCacheItemForSearchCacheTable(
HashMap<String, ArrayList<String>> map, String searchText) {
for (String category : getCategories())
map.put(category, getPartLists(category, searchText, null));
String category;
for (int j = 0; j < 26; j++) {
category = Character.toString((char) ('A' + j));
map.put(category, getPartLists(category, searchText, null));
}
}
public ArrayList<String> getCategories() {
return categoryList;
}
public ArrayList<String> getPartLists(String searchText,
PartDomainT searchDomain) {
ArrayList<String> resultList = new ArrayList<String>();
for (String category : getCategories())
resultList.addAll(getPartLists(category, searchText, searchDomain));
String category;
for (int j = 0; j < 26; j++) {
category = Character.toString((char) ('A' + j));
resultList.addAll(getPartLists(category, searchText, searchDomain));
}
return resultList;
}
public ArrayList<String> getPartLists(String category, String searchText,
PartDomainT searchDomain) {
if (searchText != null) {
searchText = searchText.replaceAll(" ", " ");
searchText = searchText.trim();
}
ArrayList<String> resultTemp = getPartLists2(category, searchText);
if (resultTemp == null)
resultTemp = new ArrayList<String>();
ArrayList<String> result = new ArrayList<String>();
ArrayList<String> tempList = null;
if (searchText != null && searchText.contains("x")) {
searchText = searchText.replaceAll("x", " x ");
searchText = searchText.replaceAll(" ", " ");
searchText = searchText.trim();
tempList = getPartLists2(category, searchText);
for (String item : tempList)
if (resultTemp.contains(item) == false)
resultTemp.add(item);
Collections.sort(resultTemp, this);
}
// filtering for searchDomain
if (searchDomain == null)
return resultTemp;
if (searchDomain == PartDomainT.LDRAW) {
for (String fileName : resultTemp) {
String brickName = fileToBrickName.get(fileName).toLowerCase();
fileName = fileName.toLowerCase();
boolean isMatched = false;
if (brickName.contains(searchText)
|| fileName.startsWith(searchText)
|| getRepresentPartName(fileName)
.startsWith(searchText))
isMatched = true;
if (isMatched)
result.add(fileName);
}
} else if (searchDomain == PartDomainT.BRICKLINK) {
for (String fileName : resultTemp) {
String brickName = fileToBrickName.get(fileName).toLowerCase();
fileName = fileName.toLowerCase();
boolean isMatched = false;
PartIds ids = CompatiblePartManager.getInstance().getPartIds(
PartDomainT.LDRAW,
LDrawUtilities.excludeExtensionFromPartName(fileName));
if (ids != null) {
if (ids.getId(PartDomainT.BRICKLINK) != null)
for (String id : ids.getId(PartDomainT.BRICKLINK))
if (id.startsWith(searchText.replaceAll(" ", ""))) {
isMatched = true;
}
}
if (brickName.contains(searchText))
isMatched = true;
if (isMatched)
result.add(fileName);
}
}
return result;
}
private ArrayList<String> getPartLists2(String category, String searchText) {
ArrayList<String> list = new ArrayList<String>();
if (isSearchCacheTalbeReady) {
list = getPartListsFromCache(category, searchText);
if (list != null) {
return list;
}
}
if (searchText == null || searchText.equals("")) {
if (category == null) {
return list;
} else {
if (categoryToFileCache.containsKey(category)) {
return categoryToFileCache.get(category);
}
}
} else {
list = new ArrayList<String>();
searchText = searchText.toLowerCase();
String brickName;
if (category == null) {
String fileName;
for (Entry<String, String> entry : fileToBrickName.entrySet()) {
brickName = entry.getValue().toLowerCase();
fileName = entry.getKey().toLowerCase();
boolean isMatched = false;
if (brickName.contains(searchText)
|| fileName.startsWith(searchText)
|| getRepresentPartName(fileName).startsWith(
searchText))
isMatched = true;
PartIds ids = CompatiblePartManager
.getInstance()
.getPartIds(
PartDomainT.LDRAW,
LDrawUtilities
.excludeExtensionFromPartName(fileName));
if (ids != null)
if (ids.getId(PartDomainT.BRICKLINK) != null)
for (String id : ids.getId(PartDomainT.BRICKLINK))
if (id.startsWith(searchText))
isMatched = true;
if (isMatched)
list.add(fileName);
}
} else {
if (categoryToFileCache.containsKey(category)) {
ArrayList<String> searchDomain = null;
if (isSearchCacheTalbeReady)
for (int i = searchText.length() - 1; i > 0; i--) {
searchDomain = getPartListsFromCache(category,
searchText.substring(0, i));
if (searchDomain != null)
break;
}
if (searchDomain == null)
searchDomain = categoryToFileCache.get(category);
for (String fileName : searchDomain) {
brickName = fileToBrickName.get(fileName).toLowerCase();
fileName = fileName.toLowerCase();
boolean isMatched = false;
if (brickName.contains(searchText)
|| fileName.startsWith(searchText)
|| getRepresentPartName(fileName).startsWith(
searchText))
isMatched = true;
PartIds ids = CompatiblePartManager
.getInstance()
.getPartIds(
PartDomainT.LDRAW,
LDrawUtilities
.excludeExtensionFromPartName(fileName));
if (ids != null) {
if (ids.getId(PartDomainT.BRICKLINK) != null)
for (String id : ids
.getId(PartDomainT.BRICKLINK))
if (id.startsWith(searchText))
isMatched = true;
}
if (isMatched)
list.add(fileName);
}
}
}
Collections.sort(list, this);
}
addSearchResultToSearchCacheTable(category, searchText, list);
return list;
}
private void addSearchResultToSearchCacheTable(String category,
String searchText, ArrayList<String> searchResult) {
if (isSearchCacheTalbeReady == false)
return;
if (searchText == null || searchText.equals(""))
return;
if (category == null || category.equals(""))
return;
HashMap<String, ArrayList<String>> map = null;
if (searchCacheTable.containsKey(searchText))
map = searchCacheTable.get(searchText);
else {
map = new HashMap<String, ArrayList<String>>();
searchCacheTable.put(searchText, map);
}
if (map.containsKey(category) == false)
map.put(category, searchResult);
}
private ArrayList<String> getPartListsFromCache(String category,
String searchText) {
if (searchCacheTable.containsKey(searchText)) {
HashMap<String, ArrayList<String>> partMap = searchCacheTable
.get(searchText);
return partMap.get(category);
}
return null;
}
public String getPartName(String fileName) {
return fileToBrickName.get(fileName);
}
public boolean contains(String key) {
return fileToBrickName.containsKey(key);
}
private void loadToPartCachePerCategory() {
for (String categoryName : categoryList) {
categoryToFileCache.put(categoryName, new ArrayList<String>());
}
String brickDescription, fileName;
for (Entry<String, String> entry : fileToBrickName.entrySet()) {
fileName = entry.getKey();
brickDescription = entry.getValue().trim();
categoryToFileCache.get("All").add(fileName);
for (String categoryName : categoryList) {
if (brickDescription.startsWith(categoryName)) {
categoryToFileCache.get(categoryName).add(fileName);
}
}
}
for (ArrayList<String> list : categoryToFileCache.values())
Collections.sort(list, this);
}
private void loadPartInfoToCache(String partsPath) {
HashMap<String, String> fileCache = new HashMap<String, String>();
BufferedReader reader = null;
String fileName, partDescription, alias = "";
File cache = new File(CACHENAME);
if (cache.exists()) {
try {
reader = new BufferedReader(new FileReader(cache));
while ((fileName = reader.readLine()) != null
&& !fileName.equals("")) {
if (fileName.startsWith(FILEPREFIX)) {
partDescription = reader.readLine().replaceAll("\\s+",
" ");
fileCache.put(fileName.substring(FILEPREFIX.length()),
partDescription);
alias = reader.readLine().replaceAll("\\s+", " ");
if (alias != null && alias.equals("") == false
&& alias.equals("null") == false) {
// System.out.println("Alias: "+fileName.substring(FILEPREFIX.length())+
// "->"+alias);
aliasPartNameMap.put(
fileName.substring(FILEPREFIX.length()),
alias);
}
} else {
reader.close();
cache.delete();
fileCache.clear();
break;
}
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
try {
reader.close();
} catch (Exception e2) {
e2.printStackTrace();
}
cache.delete();
fileCache.clear();
}
}
try {
InputStream is = ResourceManager.getInstance().getInputStream(
CACHENAME);
if (is != null) {
reader = new BufferedReader(new InputStreamReader(is));
while ((fileName = reader.readLine()) != null
&& !fileName.equals("")) {
if (fileName.startsWith(FILEPREFIX)) {
fileName = fileName.substring(FILEPREFIX.length());
if (!fileCache.containsKey(fileName)) {
partDescription = reader.readLine().replaceAll(
"\\s+", " ");
fileCache.put(fileName, partDescription);
alias = reader.readLine().replaceAll("\\s+", " ");
if (alias != null && alias.equals("") == false) {
System.out.println("Alias: " + fileName + "->"
+ alias);
aliasPartNameMap.put(fileName, alias);
}
} else {
reader.readLine();
}
} else {
reader.close();
break;
}
}
reader.close();
}
} catch (Exception e) {
e.printStackTrace();
try {
reader.close();
} catch (Exception e2) {
e2.printStackTrace();
}
}
File parts = new File(partsPath);
File[] lists = parts.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.endsWith("dat");
}
});
if (lists == null) {
return;
}
boolean readOnly = false;
try {
BufferedWriter writer = null;
for (File file : lists) {
fileName = file.getName();
partDescription = fileCache.get(fileName);
if (partDescription == null) {
reader = new BufferedReader(new FileReader(file));
partDescription = reader.readLine().substring(2)
.replaceAll("\\s+", " ");
if (partDescription.startsWith("~Moved")) {
alias = partDescription.split("\\s+")[2] + ".dat";
aliasPartNameMap.put(fileName, alias);
} else if (partDescription.startsWith("=")) {
String line = "";
while ((line = reader.readLine()) != null) {
if (line.startsWith("0 // Alias of ")) {
if (line.contains(","))
alias = line.substring(
"0 // Alias of ".length(),
line.indexOf(","))
+ ".dat";
else if (line.contains(";"))
alias = line.substring(
"0 // Alias of ".length(),
line.indexOf(";"))
+ ".dat";
else
alias = line.substring("0 // Alias of "
.length()) + ".dat";
aliasPartNameMap.put(fileName, alias);
break;
}
}
} else {
alias = "";
}
reader.close();
if (!readOnly) {
try {
if (writer == null) {
writer = new BufferedWriter(new FileWriter(
cache, true));
}
writer.write(FILEPREFIX + fileName);
writer.newLine();
writer.write(partDescription);
writer.newLine();
writer.write(alias);
writer.newLine();
} catch (Exception e) {
readOnly = true;
}
}
}
fileToBrickName.put(fileName, partDescription);
}
if (writer != null)
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
loadToPartCachePerCategory();
}
@Override
public int compare(String o1, String o2) {
return fileToBrickName.get(o1).compareTo(fileToBrickName.get(o2));
}
public String getRepresentPartName(String partName) {
String temp = partName;
String representName = partName;
HashMap<String, Boolean> history = new HashMap<String, Boolean>();
history.put(partName, true);
while ((temp = aliasPartNameMap.get(representName)) != null) {
if (history.containsKey(temp))
break;
representName = temp;
history.put(temp, true);
}
history = null;
return representName;
}
public ArrayList<String> getAllParts() {
ArrayList<String> retList = new ArrayList<String>();
for (String partName : fileToBrickName.keySet())
retList.add(LDrawUtilities.excludeExtensionFromPartName(partName));
return retList;
}
public void reInit() {
_instance = null;
}
public void loadCategoryFromCode() {
if (categoryList == null)
categoryList = new ArrayList<String>();
else
categoryList.clear();
categoryList.add("All");
categoryList.add("Brick");
categoryList.add("Plate");
categoryList.add("Tile");
categoryList.add("Slope");
categoryList.add("Minifig");
categoryList.add("Baseplate");
categoryList.add("Electric");
categoryList.add("Technic");
categoryList.add("Technic Axle");
categoryList.add("Train");
categoryList.add("Hinge");
}
public void loadCategoryFromFile() {
if (categoryList == null)
categoryList = new ArrayList<String>();
else
categoryList.clear();
File categoryFile = new File(CATEGORYPATH);
if (categoryFile.exists()) {
try {
BufferedReader reader = new BufferedReader(new FileReader(
categoryFile));
String line;
while ((line = reader.readLine()) != null) {
if (line.trim().equals(""))
continue;
categoryList.add(line.trim());
}
reader.close();
} catch (Exception e) {
e.printStackTrace();
categoryFile.delete();
}
} else {
loadCategoryFromCode();
writeCategoryToFile();
}
}
public void writeCategoryToFile() {
File categoryFile = new File(CATEGORYPATH);
String contents = "";
for (String categoryName : categoryList)
contents += categoryName + "\r\n";
try {
FileWriter fw = new FileWriter(categoryFile);
fw.write(contents);
fw.flush();
fw.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}